# core/file_utils.py
# 文件处理核心模块，负责文件列表获取、分类、排序和重命名等操作
import os
from pathlib import Path
from core.config import FILE_EXTENSIONS, SORT_PRIORITY, DEFAULT_SETTINGS

class FileRenamer:
    """
    文件批量重命名核心处理器
    功能：文件过滤/分类/排序/重命名全流程处理
    设计模式：策略模式（通过配置动态改变命名规则）
    """

    def __init__(self):
        """初始化重命名器并加载配置"""
        self.settings = {
            **DEFAULT_SETTINGS,  # 合并默认配置
            'total_count': 0     # 文件总数（用于序号补零计算）
        }

    def get_file_list(self, target_dir, file_type):
        """
        获取过滤后的文件列表
        Args:
            target_dir (str): 目标目录绝对路径
            file_type (int): 文件类型索引（0=所有文件，1-7=具体类型，8=文件夹）
        Returns:
            list: 符合要求的文件/文件夹名称列表（按原始顺序）
        Raises:
            FileNotFoundError: 目录不存在
            RuntimeError: 目录读取失败
        实现细节：
            1. 过滤隐藏文件（以.开头）和.ini配置文件
            2. 处理特殊类型8（文件夹）
            3. 其他类型通过扩展名匹配
        """
        # 添加路径标准化处理
        target_dir = os.path.normpath(target_dir)
        if not os.path.isabs(target_dir):
            target_dir = os.path.abspath(target_dir)
        if not os.path.exists(target_dir):
            raise FileNotFoundError(f"目录不存在: {target_dir}")

        try:
            # 获取并初步过滤目录内容
            all_items = os.listdir(target_dir)
            filtered_items = [
                f for f in all_items
                if not f.startswith('.') and not f.endswith('.ini')
            ]
        except Exception as e:
            raise RuntimeError(f"目录读取失败: {str(e)}")

        # 类型索引映射（GUI下拉框索引 -> 配置键名）
        type_mapping = {
            1: "IMAGE", 2: "VIDEO", 3: "DOCUMENT",
            4: "AUDIO", 5: "ARCHIVE", 6: "CODE", 7: "EBOOK", 8: "DIRECTORY"
        }

        if file_type == 0:  # 所有文件模式
            return filtered_items
        elif file_type == 8:  # 文件夹特殊处理
            return [f for f in filtered_items
                   if os.path.isdir(os.path.join(target_dir, f))]
        else:  # 按扩展名过滤具体类型
            category = type_mapping.get(file_type)
            return self._filter_by_category(category, filtered_items, target_dir)

    @staticmethod
    def _filter_by_category(category, files, target_dir):
        """
        按扩展名分类过滤（静态方法）
        Args:
            category (str): 文件分类（对应FILE_EXTENSIONS键）
            files (list): 待过滤文件列表
            target_dir (str): 用于构建完整路径
        Returns:
            list: 符合该分类的文件列表
        注意：
            - 严格区分大小写（统一转换为小写匹配）
            - 自动排除文件夹（仅处理文件）
        """
        exts = FILE_EXTENSIONS.get(category, [])
        return [
            f for f in files
            if os.path.isfile(os.path.join(target_dir, f)) and
            Path(f).suffix.lower() in exts  # 统一小写比较
        ]

    @staticmethod
    def classify_files(files, target_dir):
        """
        深度文件分类（静态方法）
        Args:
            files (list): 原始文件列表
            target_dir (str): 用于路径验证
        Returns:
            dict: 分类文件字典，键为SORT_PRIORITY中的分类
        算法逻辑：
            1. 优先识别文件夹
            2. 通过后缀匹配预设分类
            3. 未匹配的归入OTHER
        """
        classified = {category: [] for category in SORT_PRIORITY}
        for f in files:
            path = os.path.join(str(target_dir), str(f))
            if os.path.isdir(path):
                classified["DIRECTORY"].append(f)
                continue

            suffix = Path(f).suffix.lower()
            # 遍历所有分类进行匹配
            for category, exts in FILE_EXTENSIONS.items():
                if suffix in exts:
                    classified[category].append(f)
                    break
            else:  # 未匹配任何分类
                classified["OTHER"].append(f)
        return classified

    def sort_files(self, files, target_dir, file_type):
        """
        多维度文件排序
        Args:
            files (list): 待排序文件列表
            target_dir (str): 用于路径验证
            file_type (int): 排序模式（0=全局排序，其他=类型内排序）
        Returns:
            list: 排序后的文件列表
        排序策略：
            模式0：按SORT_PRIORITY优先级 > 同类按扩展名字典序
            其他：按该类型扩展名的定义顺序排序
        关键点：
            - 使用len(exts)作为未定义扩展名的排序权重
            - 确保文件夹始终优先排序（当在模式0时）
        """
        if file_type == 0:  # 全局混合排序模式
            classified = self.classify_files(files, target_dir)
            sorted_files = []
            for category in SORT_PRIORITY:
                items = classified.get(category, [])
                items.sort(key=lambda x: Path(x).suffix.lower())
                sorted_files.extend(items)
            return sorted_files
        else:  # 单一类型排序模式
            type_mapping = {
                1: "IMAGE", 2: "VIDEO", 3: "DOCUMENT",
                4: "AUDIO", 5: "ARCHIVE", 6: "CODE", 7: "EBOOK", 8: "DIRECTORY"
            }
            category = type_mapping.get(file_type)
            exts = FILE_EXTENSIONS.get(category, [])
            # 排序键：扩展名在列表中的索引（不存在则排最后）
            return sorted(files,
                         key=lambda x: exts.index(Path(x).suffix.lower())
                         if Path(x).suffix.lower() in exts
                         else len(exts))

    def generate_filename(self, index, ext):
        """
        生成标准化文件名
        Args:
            index (int): 文件序号（从start_index开始）
            ext (str): 文件扩展名（含.）
        Returns:
            str: 生成的新文件名
        命名规则：
            - 补零位数根据文件总数自动计算（当zero_padding=True时）
            - 前缀与序号用下划线连接
            - 文件夹无扩展名
        示例：
            total_count=100, zero_padding=True → 补3位（100的位数）
            generate_filename(5, ".jpg") → "prefix_005.jpg"
        """
        padding = len(str(self.settings['total_count'])) if self.settings['zero_padding'] else 0
        num_str = str(index).zfill(padding)  # 自动补零
        prefix = self.settings['prefix']
        return f"{prefix}_{num_str}{ext}" if prefix else f"{num_str}{ext}"

    def rename_files(self, target_dir, files, prefix):
        """
        执行安全重命名操作（生成器）
        Args:
            target_dir (str): 目标目录绝对路径
            files (list): 已排序的文件列表
            prefix (str): 用户输入的前缀
        Yields:
            str: 成功重命名的文件名
        Raises:
            RuntimeError: 任何重命名失败的情况
        实现特点：
            - 使用生成器逐步返回结果
            - 自动处理文件夹（无扩展名）
            - 实时更新配置参数
        安全机制：
            - 使用os.rename原子操作
            - 严格处理路径类型（确保跨平台兼容）
        """
        self.settings.update({
            'prefix': prefix,
            'total_count': len(files)  # 更新总数用于补零计算
        })
        str_target_dir = str(target_dir)  # 确保Path对象转换为字符串

        for idx, filename in enumerate(files, self.settings['start_index']):
            old_path = os.path.join(str_target_dir, str(filename))
            is_dir = os.path.isdir(old_path)

            # 处理扩展名（文件夹留空）
            ext = Path(filename).suffix if not is_dir else ""

            # 生成新文件名
            new_name = self.generate_filename(idx, ext)
            new_path = os.path.join(str_target_dir, new_name)

            try:
                os.rename(old_path, new_path)  # 执行重命名
                yield new_name  # 返回处理结果
            except Exception as e:
                raise RuntimeError(f"重命名失败: {filename} → {str(e)}")